#include "../inc/sched.h"
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/cpumask.h>
#include <linux/rcupdate.h>
#include <linux/sched/rt.h>
#include <linux/sched/task.h>

#define for_class_range(class, _from, _to) \
	for (const struct sched_class **f = _from, **t = _to, **c = f;\
         c < t, class = *c; c++)

#define for_each_class(class) \
	for_class_range(class, __sched_class_highest(), __sched_class_lowest())

static void init_rq(struct rq *rq)
{
    const struct sched_class **start, **end;

    const struct sched_class *class;

    raw_spin_lock_init(&rq->__lock);

    for_each_class(class)
    {
        if (class->init_rq)
            class->init_rq(rq);
    }
}

/*
 * Perform scheduler related setup for a newly forked process p.
 * p is forked by current.
 *
 * __sched_fork() is basic setup which is also used by sched_init() to
 * initialize the boot CPU's idle task.
 */
static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
{
    init_rt_entity(p);
}

/*
 * fork()/clone()-time setup:
 */
int sched_fork(unsigned long clone_flags, struct task_struct *p)
{
    __sched_fork(clone_flags, p);
    /*
     * We mark the process as NEW here. This guarantees that
     * nobody will actually run it, and a signal or other external
     * event cannot wake it up and insert it on the runqueue either.
     */
    p->__state = TASK_NEW;

    /*
     * Make sure we do not leak PI boosting priority to the child.
     */
    p->prio = current->normal_prio;

    p->sched_class = __setscheduler_class(p->policy, p->prio);

    return 0;
}

void __init init_idle(struct task_struct *idle, int cpu)
{
    struct rq *rq = cpu_rq(cpu);

    idle->sched_class = &idle_sched_class;
    init_thread_info(idle);

    idle->__state = TASK_RUNNING;

    rq->idle = idle;

    rcu_assign_pointer(rq->curr, idle);
}

void __init sched_init(void)
{
    int i;

    for_each_possible_cpu(i)
    {
        struct rq *rq;

        rq = cpu_rq(i);

        init_rq(rq);
    }

    init_idle(current, smp_processor_id());
}
